﻿/********************************************************************************
    Copyright (C) Binod Nepal, Planet Earth Solutions Pvt. Ltd., Kathmandu.
	Released under the terms of the GNU General Public License, GPL, 
	as published by the Free Software Foundation, either version 3 
	of the License, or (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
***********************************************************************************/

using System;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Management;
using System.Text;
using Pes.Utility;
using System.IO.Ports;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using GsmComm.GsmCommunication;
using GsmComm.Interfaces;
using GsmComm.Server;
using GsmComm.PduConverter;
using System.Data.SqlClient;

namespace Pes.Messaging.ApplicationLayer
{

    public static class Program
    {
        static GsmCommMain adapter = new GsmCommMain();

        public static void StartWork()
        {
            ProcessEmails();
            ProcessTexts();
            LogProvider.log.Debug("Back to the wait.");
        }

        private static void ProcessEmails()
        {
            Console.ForegroundColor = ConsoleColor.Yellow;

            LogProvider.log.Debug("Now requesting the email queue.");

            using (DataTable table = Pes.Messaging.DatabaseLayer.Emails.GetEmailQueue())
            {
                if (table.Rows.Count > 0)
                {
                    foreach (DataRow row in table.Rows)
                    {
                        string id = Conversion.TryCastString(row["OutgoingEmailId"]);
                        string applicationId = Conversion.TryCastString(row["ApplicationId"]);
                        string applicationName = Conversion.TryCastString(row["ApplicationName"]);
                        string recipients = Conversion.TryCastString(row["EmailAddress"]);
                        string subject = Conversion.TryCastString(row["Subject"]);
                        string message = Conversion.TryCastString(row["Message"]);
                        string sentByEmail = Conversion.TryCastString(row["SentBy"]);
                        string senderName = Conversion.TryCastString(row["EmailFrom"]);
                        string host = Conversion.TryCastString(row["Host"]);
                        int port = Conversion.TryCastInteger(row["Port"]);
                        bool enableSsl = Conversion.TryCastBoolean(row["EnableSsl"]);
                        string userName = Conversion.TryCastString(row["UserName"]);
                        string password = Conversion.TryCastString(row["Password"]);

                        if (port.Equals(int.MinValue))
                        {
                            port = 21;
                        }

                        Console.ForegroundColor = ConsoleColor.White;
                        LogProvider.log.Debug("A new email found in the queue.");
                        LogProvider.log.DebugFormat("Application Id : {0}", applicationId);
                        LogProvider.log.DebugFormat("Application Name : {0}", applicationName);
                        LogProvider.log.DebugFormat("Recipients : {0}", recipients);
                        LogProvider.log.DebugFormat("Subject : {0}", subject);

                        Emails.Processor.Send(senderName, recipients, subject, message, host, port, enableSsl, userName, password, id);
                    }

                    Console.ForegroundColor = ConsoleColor.Yellow;
                    LogProvider.log.Debug("All email processessed sucessfully. Returning back to the main thread.");
                }
                else
                {
                    LogProvider.log.Debug("Nothing found in the email queue. Returning back to the main thread.");
                }
            }
        }

        private static void ProcessTexts()
        {
            Console.WriteLine();
            LogProvider.log.Debug("Testing available device interfaces for text messaging.");

            LogProvider.log.Debug("Now listing all available COM Ports.");
            string[] ports = SerialHelper.AvilablePorts();

            if (ports.Count() > 0)
            {
                foreach (string port in ports)
                {
                    try
                    {
                        LogProvider.log.DebugFormat("Trying to connect on port {0}.", port);

                        adapter = new GsmCommMain(port);
                        adapter.Open();

                        if (adapter.IsConnected())
                        {
                            LogProvider.log.DebugFormat("Connection was successful on port {0}.", port);
                            Console.WriteLine();
                            LogProvider.log.DebugFormat("Trying to identify device on port {0}.", port);
                            LogProvider.log.DebugFormat("Manufacturer: {0}. \nModel: {1}. Serial Number: {2}. Revision: {3}.", adapter.IdentifyDevice().Manufacturer, adapter.IdentifyDevice().Model, adapter.IdentifyDevice().SerialNumber, adapter.IdentifyDevice().Revision);
                            LogProvider.log.Debug("Device identified sucessfully.");
                            Console.WriteLine();

                            LogProvider.log.DebugFormat("Closing the port {0}.", port);
                            adapter.Close();
                            LogProvider.log.DebugFormat("The port {0} is now closed.", port);

                            LogProvider.log.Debug("Device interface test completed successfully.");

                            ProcessTexts(port);
                            CheckNewTextMessage(port);
                            break;
                        }
                        else
                        {
                            LogProvider.log.DebugFormat("Could not connect to port {0}.", port);
                            LogProvider.log.DebugFormat("Closing the port {0}.", port);
                            adapter.Close();
                            LogProvider.log.DebugFormat("The port {0} is now closed.", port);
                        }
                    }
                    catch (Exception ex)
                    {
                        ConsoleColor temp = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.Red;
                        LogProvider.log.ErrorFormat("Error trapped. {0}", ex.Message);
                        Console.ForegroundColor = temp;
                    }
                    finally
                    {
                        if (adapter.IsOpen())
                        {
                            LogProvider.log.DebugFormat("Closing the port {0}.", port);
                            adapter.Close();
                            LogProvider.log.DebugFormat("The port {0} is now closed.", port);
                        }
                    }

                }
            }
            else
            {
                LogProvider.log.Debug("No COM port found.");
            }
        }

        private static void CheckNewTextMessage(string port)
        {
            try
            {
                Console.WriteLine();
                LogProvider.log.DebugFormat("Now checking new text messages on port {0}.", port);

                adapter = new GsmCommMain(port);
                LogProvider.log.DebugFormat("Connecting to port {0}.", port);
                adapter.Open();

                if (adapter.IsConnected())
                {
                    LogProvider.log.DebugFormat("Connection was successful on port {0}.", port);

                    LogProvider.log.DebugFormat("Checking message inbox on port {0}.", port);

                    string storage = "SM"; //SIM Card
                    DecodedShortMessage[] textMessages = adapter.ReadMessages(PhoneMessageStatus.All, storage);

                    if (textMessages.Count() > 0)
                    {
                        foreach (DecodedShortMessage textMessage in textMessages)
                        {
                            if (textMessage.Data is SmsDeliverPdu)
                            {
                                SmsDeliverPdu data = textMessage.Data as SmsDeliverPdu;
                                string cellNumber = data.OriginatingAddress;
                                string message = data.UserDataText;
                                int index = textMessage.Index;

                                LogProvider.log.DebugFormat("A new message has arrived on port {0}.", port);
                                LogProvider.log.DebugFormat("Sent by : {0}.", cellNumber);
                                LogProvider.log.DebugFormat("Message : {0}.", message);

                                LogProvider.log.Debug("Now saving the message to the database repository.");
                                Pes.Messaging.DatabaseLayer.Texts.SaveMessage(cellNumber, message);
                                LogProvider.log.Debug("The message was successfully saved to the database repository.");
                                LogProvider.log.DebugFormat("Now deleting the message #{0} from the SIM storage on port {1}.", index.ToString(), port);
                                adapter.DeleteMessage(index, storage);
                                LogProvider.log.DebugFormat("The message #{0} was deleted from SIM storage on port {1}.", index.ToString(), port);
                                Console.WriteLine();
                            }
                        }

                    }
                    else
                    {
                        LogProvider.log.DebugFormat("No new messages found on port {0}.", port);
                    }
                }
                else
                {
                    LogProvider.log.DebugFormat("Could not connect to port {0}.", port);
                    LogProvider.log.DebugFormat("Closing the port {0}.", port);
                    adapter.Close();
                    LogProvider.log.DebugFormat("The port {0} is now closed.", port);
                }
            }
            catch (SqlException)
            {
                throw;
            }
            catch (Exception ex)
            {
                ConsoleColor temp = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                LogProvider.log.ErrorFormat("Error trapped. {0}", ex.Message);
                Console.ForegroundColor = temp;
            }
            finally
            {
                if (adapter.IsOpen())
                {
                    LogProvider.log.DebugFormat("Closing the port {0}.", port);
                    adapter.Close();
                    LogProvider.log.DebugFormat("The port {0} is now closed.", port);
                }
            }

        }

        private static void ProcessTexts(string port)
        {
            try
            {
                Console.WriteLine();
                LogProvider.log.Debug("Now requesting the text message queue.");

                using (DataTable table = Pes.Messaging.DatabaseLayer.Texts.GetTextQueue())
                {
                    if (table.Rows.Count > 0)
                    {
                        foreach (DataRow row in table.Rows)
                        {
                            string id = Conversion.TryCastString(row["OutgoingTextId"]);
                            string applicationId = Conversion.TryCastString(row["ApplicationId"]);
                            string applicationName = Conversion.TryCastString(row["ApplicationName"]);
                            string cellNumber = Conversion.TryCastString(row["CellNumber"]);
                            string message = Conversion.TryCastString(row["Message"]);


                            ConsoleColor temp = Console.ForegroundColor;
                            Console.ForegroundColor = ConsoleColor.White;
                            LogProvider.log.Debug("A new text message found in the queue.");
                            LogProvider.log.DebugFormat("Text Id : {0}", id);
                            LogProvider.log.DebugFormat("Application Id : {0}", applicationId);
                            LogProvider.log.DebugFormat("Application Name : {0}", applicationName);
                            LogProvider.log.DebugFormat("Recipient : {0}", cellNumber);
                            LogProvider.log.DebugFormat("Message : {0}", message);
                            Console.ForegroundColor = temp;

                            SendMessage(port, cellNumber, message, id);
                        }

                        LogProvider.log.Debug("All text messages processessed sucessfully. Returning back to the main thread.");
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        LogProvider.log.Debug("Nothing found in the text messaging queue. Returning back to the main thread.");
                    }
                }
            }
            catch (SqlException)
            {
                throw;
            }
            catch (Exception ex)
            {
                ConsoleColor temp = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                LogProvider.log.ErrorFormat("Error trapped. {0}", ex.Message);
                Console.ForegroundColor = temp;
            }
            finally
            {
                if (adapter.IsOpen())
                {
                    LogProvider.log.DebugFormat("Closing the port {0}.", port);
                    adapter.Close();
                    LogProvider.log.DebugFormat("The port {0} is now closed.", port);
                }
            }
        }

        private static void SendMessage(string port, string number, string message, string id)
        {
            Console.WriteLine();
            LogProvider.log.DebugFormat("Now trying to send text message via port {0}.", port);

            adapter = new GsmCommMain(port);
            adapter.Open();

            if (adapter.IsConnected())
            {
                LogProvider.log.DebugFormat("Connection was successful on port {0}.", port);
                SmsSubmitPdu pdu = new SmsSubmitPdu(message, number);
                adapter.SendMessage(pdu);
            }
            else
            {
                LogProvider.log.DebugFormat("Could not connect to port {0}.", port);
                LogProvider.log.DebugFormat("Closing the port {0}.", port);
                adapter.Close();
                LogProvider.log.DebugFormat("The port {0} is now closed.", port);
            }

            LogProvider.log.DebugFormat("The message {0} was sent successfully.", id);
            Pes.Messaging.DatabaseLayer.Texts.FlagSent(id);
        }

        public static int GetPollInterval()
        {
            return Convert.ToInt32(ConfigurationManager.AppSettings["PollInterVal"]);
        }
    }
}
